﻿#include "stdafx.h"
#include "CommonFunction.h"
#include <windows.h>


// This structure is used internally by the XSleep function 
struct XSleep_Structure
{
	int duration;
	HANDLE eventHandle;
};

//////////////////////////////////////////////////////////////////////
// Function  : XSleepThread()
// Purpose   : The thread which will sleep for the given duration
// Returns   : DWORD WINAPI
// Parameters:       
//  1. pWaitTime -
//////////////////////////////////////////////////////////////////////
DWORD WINAPI XSleepThread(LPVOID pWaitTime)
{
	XSleep_Structure *sleep = (XSleep_Structure *) pWaitTime;

	Sleep(sleep->duration);
	SetEvent(sleep->eventHandle);

	return 0;
}

/////////////////////////////////////////////////////////////////////
// Function  : XSleep()
// Purpose   : To make the application sleep for the specified time
//             duration.
//             Duration the entire time duration XSleep sleeps, it
//             keeps processing the message pump, to ensure that all
//             messages are posted and that the calling thread does
//             not appear to block all threads!
// Returns   : none
// Parameters:       
//  1. nWaitInMSecs - Duration to sleep specified in miliseconds.
//////////////////////////////////////////////////////////////////////
DWORD XSleep(int nWaitInMSecs)
{
	XSleep_Structure sleep;

	sleep.duration = nWaitInMSecs;
	sleep.eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);

	DWORD threadId = 0;
	CreateThread(NULL, 0, &XSleepThread, &sleep, 0, &threadId);

	MSG msg;

	while(::WaitForSingleObject(sleep.eventHandle, 0) == WAIT_TIMEOUT)
	{
		//get and dispatch messages
		if(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
            if (msg.message == WM_SLEEP_THRED_STOP)
			{  
				ExitThread(threadId);
				return threadId;      //线程正常返回，会释放局部变量等内存资源
			}
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}		
	}

	CloseHandle(sleep.eventHandle);
	return threadId;
}

int MyAfxMessageBox(LPCTSTR lpszFormat, ...)
{
	if (!lpszFormat)
	{
		return 0;
	}
	va_list va;
	TCHAR OutText[4096];

	va_start(va, lpszFormat);
	//
	// Truncation is acceptable.
	//
	StringCbVPrintf(OutText, sizeof(OutText), lpszFormat, va);
	va_end(va);
	return AfxMessageBox(OutText);
}


int SQLRand()
{
	return (int)((double)rand() / (RAND_MAX + 1) * (1000 - 0) + 0);
}

int GetCollectCount(_RecordsetPtr& pPtr)
{
#if 0
	return pPtr->GetRecordCount();
#else
	int sum = 0;
	do 
	{
		if (pPtr == NULL)
		{
			break;
		}
		if(!pPtr->GetBOF())
			pPtr->MoveFirst();
		while(!pPtr->GetadoEOF())
		{
			sum++;
			pPtr->MoveNext();
		}
		pPtr->MoveFirst();
	} while (FALSE);

	return sum;
#endif
}

CString MyFormatMessage(DWORD dwMsgId)
{
	TCHAR szErr[1024];
	DWORD dwLangId = 0;//MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
	DWORD dwErr = ERROR_SUCCESS;

	StringCchPrintf(szErr, _countof(szErr), _T("未知错误，错误码：0x%08x"),
		dwMsgId);
	if (!::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, dwMsgId, dwLangId, szErr, _countof(szErr), NULL))
	{
		HMODULE hDll = ::LoadLibrary(_T("netmsg.dll"));
		if (hDll)
		{
			if (!::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
				hDll, dwMsgId, dwLangId, szErr, _countof(szErr), NULL))
			{
				dwErr = GetLastError();
			}
			::FreeLibrary(hDll);
		}
	}
	return CString(szErr);
}


DWORD MyRemoveDir(LPCTSTR strPath)
{
	DWORD dwErr = ERROR_SUCCESS;

	do 
	{
		//never remove root!
		if (::PathIsRoot(strPath))
		{
			TRACE(_T("is root, do nothing!\n"));
			break;
		}
#if 1
		CString strTmp;
		CFileFind finder;
		BOOL bWorking;

		if (!::PathIsDirectory(strPath))
		{
			dwErr = ERROR_INVALID_PARAMETER;
			TRACE(_T("is not dir!\n"));
			break;
		}
		strTmp.Format(_T("%s\\*.*"), strPath);
		bWorking = finder.FindFile(strTmp);

		while(bWorking)
		{
			bWorking = finder.FindNextFile();

			strTmp = finder.GetFilePath();
			if (finder.IsDots())
			{
				continue;
			}
			if (finder.IsDirectory())
			{
				TRACE(_T("remove sub dir:%s\n"), strTmp);
				dwErr = MyRemoveDir(strTmp);
				if (ERROR_SUCCESS != dwErr)
				{
					TRACE(_T("delete %s error:%s\n"), strTmp, MyFormatMessage(dwErr));
					break;
				}
				continue;
			}
			TRACE(_T("delete file:%s\n"), strTmp);
			if (finder.IsReadOnly())
			{
				TRACE(_T("file is readonly, clear it.\n"));
				DWORD dwAttr = ::GetFileAttributes(strTmp);
				dwAttr &= (~FILE_ATTRIBUTE_READONLY);
				::SetFileAttributes(strTmp, dwAttr);
			}
			if (!::DeleteFile(strTmp))
			{
				dwErr = GetLastError();
				TRACE(_T("delete file failed, return:%d\n"), dwErr);
				break;
			}
		}
		if (ERROR_SUCCESS != dwErr)
		{
			//some error
			break;
		}
		TRACE(_T("all sub dir should be deleted, del %s now\n"), strPath);
		finder.Close();
		//进程的CurrentDirectory也会占用该文件句柄，所以如果要对该目录进行删除的话，就需要先把当前目录设成和这个没有关系的其他目录。
		TCHAR szCurrent[1024] = {_T('\0'),};
		::GetCurrentDirectory(_countof(szCurrent), szCurrent);
		if (!::PathIsRoot(szCurrent))
		{
			TCHAR szT1[MAX_PATH], szT2[MAX_PATH];
			::PathCanonicalize(szT1, szCurrent);
			::GetFullPathName(szT1, _countof(szCurrent), szCurrent, NULL);
			::PathCanonicalize(szT2, strPath);
			if (lstrcmpi(szCurrent, szT2) == 0)
			{
				::PathRemoveFileSpec(szCurrent);
				::SetCurrentDirectory(szCurrent);
			}
		}
		if (!::RemoveDirectory(strPath))
		{
			dwErr = GetLastError();
		}
#else
		CString strCmd = _T("rmdir");
		CString strParam;
		strParam.Format(_T("/s /q \"%s\""), strPath);
		::ShellExecute(NULL, _T("open"), strCmd, strParam, CPaintManagerUI::GetInstancePath(), SW_HIDE);
#endif

	} while (false);

	return dwErr;
}

bool IncludeChinese(LPCTSTR pstrString)
{
	int i, n = lstrlen(pstrString);
	int c;
#if defined(UNICODE) || defined(_UNICODE)
	//UNICODE编码，汉字在0x4e00~0x9fbb（4.1）或0x4e00~0x9fc3（5.1）
	//Windows XP采用UTF16
	//0x3400~0x4db5
	//0x4e00~9fc3
	//0xf900~fa20
	//0xfa30~0xfa6a
	//0xfa70~0xfad9
	//0x20000~0x2a6d6
	//0x2d800~0x2fa1d
	for (i = 0; i < n; i++)
	{
		c = (int)(*pstrString);
		if ( (c >= 0x4e00) &&
			(c <= 0x9fc3) )
		{
			return true;
		}
		pstrString++;
	}
	return false;
#else
	//假定（也只支持）为GB2312编码,高位0XB0-0XF7，低位是0XA1-0XFE
	//DBCS编码,第一字节>=0xB0，第二字节>=0xa1
	n--;
	for (i = 0; i < n; i++)
	{
		c = pstrString[i];
		if (c >= 0xb0 &&
			c <= 0xf7)
		{
			c = pstrString[i+1];
			if (c >= 0xa1 &&
				c <= 0xfe)
			{
				return true;
			}
			//也认为是中文?
		}
	}
	return false;
#endif
}

bool n_equal ( TCHAR elem1, TCHAR elem2 )
{
	return ((elem1 == _T('\n')) && (elem2 == _T('\n')));
}

bool s_equal ( TCHAR elem1, TCHAR elem2 )
{
	return ((elem1 == _T(' ')) && (elem2 == _T(' ')));
}


template<typename T>
BOOL _IsNumeric(T strString)
{
	if (!strString || !*strString)
	{
		return FALSE;
	}

	//skip the first - char
	if (*strString == _T('-'))
	{
		strString++;
	}
	while(*strString)
	{
		if (!isdigit(*strString))
		{
			return FALSE;
		}
		strString++;
	}

	return TRUE;
}

BOOL IsNumeric(LPCSTR strString)
{
	return _IsNumeric(strString);
}

BOOL IsNumeric(LPCWSTR strString)
{
	return _IsNumeric(strString);
}

CString GetCollect(_RecordsetPtr& pPtr, long nItem)
{
	_variant_t val(nItem);
	return GetCollect(pPtr, val);

}

CString GetCollect(_RecordsetPtr& pPtr, LPCTSTR strName)
{
	_variant_t val(strName);
	return GetCollect(pPtr, val);
#if 0
	CString strVal = _T("");
	_variant_t val;

	if (pPtr == NULL)
	{
		return strVal;
	}
	try{
		val = pPtr->GetCollect(strName);
		strVal = (val.vt == VT_NULL) ? _T("") : CString(val);
	}
	catch(_com_error &e)
	{
		UNREFERENCED_PARAMETER(e);
#ifdef _DEBUG
		MyAfxMessageBox(e.Description());
#endif
		strVal.Empty();
	}

	return strVal;
#endif
}

CString GetCollect(_RecordsetPtr& pPtr, _variant_t vName)
{
	CString strVal = _T("");
	_variant_t val;

	if (pPtr == NULL)
	{
		return strVal;
	}
	try{
		val = pPtr->GetCollect(vName);
		strVal = (val.vt == VT_NULL) ? _T("") : CString(val);
	}
	catch(_com_error &e)
	{
		UNREFERENCED_PARAMETER(e);
#ifdef _DEBUG
		MyAfxMessageBox(e.Description());
#endif
		strVal.Empty();
	}

	return strVal;
}

bool IsVistaOrLater()
{
	OSVERSIONINFOEX osvi;
	DWORDLONG dwlConditionMask = 0;
	int op=VER_GREATER_EQUAL;

	// Initialize the OSVERSIONINFOEX structure.

	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
	osvi.dwMajorVersion = 6;

	// Initialize the condition mask.

	VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );

	// Perform the test.

	return VerifyVersionInfo(
		&osvi, 
		VER_MAJORVERSION,
		dwlConditionMask) ? true : false;

}

wstring& MyGetClipboardText(__in HWND hWnd, __out wstring& wstrText)
{
	UINT fmt = CF_UNICODETEXT;
	bool bOK = false;

	wstrText.empty();
	do 
	{
		if (!IsClipboardFormatAvailable(fmt))
		{
			break;
		}
		if (!OpenClipboard(hWnd))
		{
			break;
		}

		HGLOBAL   hglb = GetClipboardData(fmt); 
		if (hglb != NULL) 
		{ 
			LPCWSTR lptstr = (LPCWSTR)GlobalLock(hglb); 
			if (lptstr != NULL) 
			{
				wstrText = lptstr;
				GlobalUnlock(hglb); 
			} 
		} 
		CloseClipboard();

		bOK = true;
	}while(FALSE);

	return wstrText;
}

string UnicodeToANSI( const wstring& str )
{
	char*     pElementText;
	int    iTextLen;
	// wide char to multi char
	iTextLen = WideCharToMultiByte( CP_ACP,
		0,
		str.c_str(),
		-1,
		NULL,
		0,
		NULL,
		NULL );
	pElementText = new char[iTextLen + 1];
	memset( ( void* )pElementText, 0, sizeof( char ) * ( iTextLen + 1 ) );
	::WideCharToMultiByte( CP_ACP,
		0,
		str.c_str(),
		-1,
		pElementText,
		iTextLen,
		NULL,
		NULL );
	string strText;
	strText = pElementText;
	delete[] pElementText;
	return strText;
}


#if 0
HANDLE MyAfxBeginThread(AFX_THREADPROC pfnThreadProc,
	LPVOID pParam,
	int nPriority /*= THREAD_PRIORITY_NORMAL*/,
	UINT nStackSize /*= 0*/,
	DWORD dwCreateFlags /*= 0*/,
	LPSECURITY_ATTRIBUTES lpSecurityAttrs /*= NULL*/)
{
	HANDLE hThread = NULL;
	DWORD dwRet = ERROR_SUCCESS;

	do 
	{
		CWinThread* pThread = AfxBeginThread(pfnThreadProc, pParam, nPriority, nStackSize, dwCreateFlags, lpSecurityAttrs);
		if (NULL == pThread)
		{
			dwRet = ERROR_NOT_ENOUGH_MEMORY;
			TRACE(_T("创建线程失败\n"));
			break;
		}
		if (!::DuplicateHandle(GetCurrentProcess(), pThread->m_hThread,
			GetCurrentProcess(), &hThread, NULL, FALSE, DUPLICATE_SAME_ACCESS))
		{
			dwRet = GetLastError();
			TRACE(_T("DuplicateHandle of ad thread failed:0x%x\n"), dwRet);
			break;
		}
	} while (FALSE);

	SetLastError(dwRet);
	return (ERROR_SUCCESS == dwRet) ? hThread : NULL;
}
#endif



BOOL IsAdmin(void)
{  
	HANDLE                   hAccessToken = NULL;
	BYTE adminSID[SECURITY_MAX_SID_SIZE];
	BOOL                     bRet = FALSE;  
	DWORD dwSize;
	TOKEN_ELEVATION_TYPE TokenEleType;

	do 
	{
		if(!::OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken)) 
		{
			break;
		}

		//TokenElevationType在Vista支持，XP下返回参数错误，直接调用IsUserAnAdmin
		if (!::GetTokenInformation(hAccessToken, TokenElevationType, (LPVOID)&TokenEleType, sizeof(TokenEleType), &dwSize))
		{
			//if (ERROR_INVALID_PARAMETER == GetLastError())
			//{
			//}
			TRACE(_T("GetTokenInformation(TokenElevationType) failed:%s, size:%d\n"), MyFormatMessage(GetLastError()), dwSize);
			bRet = ::IsUserAnAdmin();
			break;
		}
		dwSize = sizeof(adminSID);
		if (!::CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &adminSID, &dwSize))
		{
			TRACE(_T("CreateWellKnownSid failed:%s\n"), MyFormatMessage(GetLastError()));
			break;
		}
		TRACE(_T("TokenEleType:%d\n"), TokenEleType);
		if (TokenElevationTypeLimited == TokenEleType)
		{
			HANDLE hUnfileterd = NULL;
			if (!::GetTokenInformation(hAccessToken, TokenLinkedToken, &hUnfileterd, sizeof(HANDLE), &dwSize))
			{
				TRACE(_T("GetTokenInformation(TokenLinkedToken) failed:%s\n"), MyFormatMessage(GetLastError()));
				break;
			}
			::CheckTokenMembership(hUnfileterd, adminSID, &bRet);
			::CloseHandle(hUnfileterd);
		}
		else
		{
			bRet = ::IsUserAnAdmin();
		}
	} while (false);

	if (hAccessToken)
	{
		CloseHandle(hAccessToken);  
	}
	return bRet;
}
#if 0
CString MyFormatMessage(DWORD dwMsgId)
{
	TCHAR szErr[1024];
	DWORD dwLangId = 0;//MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
	DWORD dwErr = ERROR_SUCCESS;

	StringCchPrintf(szErr, _countof(szErr), _T("未知错误，错误码：0x%08x"),
		dwMsgId);
	if (!::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, dwMsgId, dwLangId, szErr, _countof(szErr), NULL))
	{
		HMODULE hDll = ::LoadLibrary(_T("netmsg.dll"));
		if (hDll)
		{
			if (!::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
				hDll, dwMsgId, dwLangId, szErr, _countof(szErr), NULL))
			{
				dwErr = GetLastError();
			}
			::FreeLibrary(hDll);
		}
	}
	return CString(szErr);
}

CString CUTF8_CString(const char* strUtf8)
{
	int nLen = ::MultiByteToWideChar(CP_UTF8, 0, strUtf8, -1, NULL, 0);
	wstring wUU;
	wUU.resize(nLen);
	nLen = ::MultiByteToWideChar(CP_UTF8, 0, strUtf8, -1, &wUU[0], nLen);

	return (LPTSTR)CW2T(wUU.c_str());
}

DWORD MyRemoveDir(LPCTSTR strPath)
{
	DWORD dwErr = ERROR_SUCCESS;

	do 
	{
		//never remove root!
		if (::PathIsRoot(strPath))
		{
			TRACE(_T("is root, do nothing!\n"));
			break;
		}
#if 1
		CString strTmp;
		CFileFind finder;
		BOOL bWorking;

		if (!::PathIsDirectory(strPath))
		{
			dwErr = ERROR_INVALID_PARAMETER;
			TRACE(_T("is not dir!\n"));
			break;
		}
		strTmp.Format(_T("%s\\*.*"), strPath);
		bWorking = finder.FindFile(strTmp);

		while(bWorking)
		{
			bWorking = finder.FindNextFile();

			strTmp = finder.GetFilePath();
			if (finder.IsDots())
			{
				continue;
			}
			if (finder.IsDirectory())
			{
				TRACE(_T("remove sub dir:%s\n"), strTmp);
				dwErr = MyRemoveDir(strTmp);
				if (ERROR_SUCCESS != dwErr)
				{
					TRACE(_T("delete %s error:%s\n"), strTmp, MyFormatMessage(dwErr));
					break;
				}
				continue;
			}
			TRACE(_T("delete file:%s\n"), strTmp);
			if (finder.IsReadOnly())
			{
				TRACE(_T("file is readonly, clear it.\n"));
				DWORD dwAttr = ::GetFileAttributes(strTmp);
				dwAttr &= (~FILE_ATTRIBUTE_READONLY);
				::SetFileAttributes(strTmp, dwAttr);
			}
			if (!::DeleteFile(strTmp))
			{
				dwErr = GetLastError();
				TRACE(_T("delete file failed, return:%d\n"), dwErr);
				break;
			}
		}
		if (ERROR_SUCCESS != dwErr)
		{
			//some error
			break;
		}
		TRACE(_T("all sub dir should be deleted, del %s now\n"), strPath);
		finder.Close();
		//进程的CurrentDirectory也会占用该文件句柄，所以如果要对该目录进行删除的话，就需要先把当前目录设成和这个没有关系的其他目录。
		TCHAR szCurrent[1024] = {_T('\0'),};
		::GetCurrentDirectory(_countof(szCurrent), szCurrent);
		if (!::PathIsRoot(szCurrent))
		{
			TCHAR szT1[MAX_PATH], szT2[MAX_PATH];
			::PathCanonicalize(szT1, szCurrent);
			::GetFullPathName(szT1, _countof(szCurrent), szCurrent, NULL);
			::PathCanonicalize(szT2, strPath);
			if (lstrcmpi(szCurrent, szT2) == 0)
			{
				::PathRemoveFileSpec(szCurrent);
				::SetCurrentDirectory(szCurrent);
			}
		}
		if (!::RemoveDirectory(strPath))
		{
			dwErr = GetLastError();
		}
#else
		CString strCmd = _T("rmdir");
		CString strParam;
		strParam.Format(_T("/s /q \"%s\""), strPath);
		::ShellExecute(NULL, _T("open"), strCmd, strParam, CPaintManagerUI::GetInstancePath(), SW_HIDE);
#endif

	} while (false);

	return dwErr;
}

bool IsVistaOrLater()
{
	OSVERSIONINFOEX osvi;
	DWORDLONG dwlConditionMask = 0;
	int op=VER_GREATER_EQUAL;

	// Initialize the OSVERSIONINFOEX structure.

	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
	osvi.dwMajorVersion = 6;

	// Initialize the condition mask.

	VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );

	// Perform the test.

	return VerifyVersionInfo(
		&osvi, 
		VER_MAJORVERSION,
		dwlConditionMask) ? true : false;

}

bool IsWin7SP1OrLater()
{
	OSVERSIONINFOEX osvi;
	DWORDLONG dwlConditionMask = 0;
	int op=VER_GREATER_EQUAL;

	// Initialize the OSVERSIONINFOEX structure.

	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
	osvi.dwMajorVersion = 6;
	osvi.dwMinorVersion = 1;
	osvi.wServicePackMajor = 1;

	// Initialize the condition mask.

	VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, op );
	VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, op );
	VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, op );

	// Perform the test.

	return VerifyVersionInfo(
		&osvi, 
		VER_MAJORVERSION | VER_MINORVERSION | 
		VER_SERVICEPACKMAJOR,
		dwlConditionMask) ? true : false;
}

bool n_equal ( TCHAR elem1, TCHAR elem2 )
{
	return ((elem1 == _T('\n')) && (elem2 == _T('\n')));
}

bool s_equal ( TCHAR elem1, TCHAR elem2 )
{
	return ((elem1 == _T(' ')) && (elem2 == _T(' ')));
}

float TwipsPerPixelX()
{
	float r = 0.0f;

	HDC hDes = ::GetDC(GetDesktopWindow());
	r = 1440.0f / GetDeviceCaps(hDes, LOGPIXELSX);
	::ReleaseDC(GetDesktopWindow(), hDes);

	return r;
}

float TwipsPerPixelY()
{
	float r = 0.0f;

	HDC hDes = ::GetDC(GetDesktopWindow());
	r = 1440.0f / GetDeviceCaps(hDes, LOGPIXELSY);
	::ReleaseDC(GetDesktopWindow(), hDes);

	return r;
}
#endif
